package cn.springcloud.fix.demo.balance;

import cn.springcloud.fix.demo.balance.api.LoadBalancerClient;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.Data;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
import org.springframework.cloud.netflix.ribbon.RibbonUtils;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;

import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.Map;

public class RibbonLoadBalancerClient implements LoadBalancerClient {

    @Override
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        return this.execute(serviceId, null, request);
    }

    @Override
    public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
        ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
        Server server = this.getServer(serviceId);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonServer ribbonServer = new RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
            //return this.execute(serviceId, (ServiceInstance) ribbonServer, (LoadBalancerRequest) request);
            return null;
        }
    }

    @Override
    public URI reconstructURI(ServiceInstance instance, URI original) {
        return null;
    }

    @Override
    public ServiceInstance choose(String serviceId) {
        Server server = getServer(serviceId);
        if (server == null) {
            return null;
        }
        return null;
    }

    private Server getServer(String serviceId) {
        return getServer(getLoadBalancer(serviceId));
    }

    private Server getServer(ILoadBalancer loadBalancer) {
        if (loadBalancer == null) {
            return null;
        }
        return loadBalancer.chooseServer("default");
    }

    private ILoadBalancer getLoadBalancer(String serviceId) {
        //return this.clientFactory.getLoadBalancer(serviceId);
        return null;
    }

    private ServerIntrospector serverIntrospector(String serviceId) {
        //ServerIntrospector serverIntrospector = (ServerIntrospector) this.clientFactory.getInstance(serviceId, ServerIntrospector.class);
        //if (serverIntrospector == null) {
        //    serverIntrospector = new DefaultServerIntrospector();
        //}
        //return serverIntrospector;
        return null;
    }

    private boolean isSecure(Server server, String serviceId) {
        //IClientConfig config = this.clientFactory.getClientConfig(serviceId);
        //ServerIntrospector serverIntrospector = this.serverIntrospector(serviceId);
        //return RibbonUtils.isSecure(config, serverIntrospector, server);
        return false;
    }

    public static class RibbonServer implements ServiceInstance {
        private final String serviceId;
        private final Server server;
        private final boolean secure;
        private Map<String, String> metadata;

        public RibbonServer(String serviceId, Server server) {
            this(serviceId, server, false, Collections.emptyMap());
        }

        public RibbonServer(String serviceId, Server server, boolean secure, Map<String, String> metadata) {
            this.serviceId = serviceId;
            this.server = server;
            this.secure = secure;
            this.metadata = metadata;
        }

        public String getInstanceId() {
            return this.server.getId();
        }

        public String getServiceId() {
            return this.serviceId;
        }

        public String getHost() {
            return this.server.getHost();
        }

        public int getPort() {
            return this.server.getPort();
        }

        public boolean isSecure() {
            return this.secure;
        }

        public URI getUri() {
            return DefaultServiceInstance.getUri(this);
        }

        public Map<String, String> getMetadata() {
            return this.metadata;
        }

        public Server getServer() {
            return this.server;
        }

        public String getScheme() {
            return this.server.getScheme();
        }
    }
}
